import 'dart:math';


class Point {
  final double x;
  final double y;

  Point(this.x, this.y);


  factory Point.fromJson(Map<String, double> json) {
    return Point(json['x']!, json['y']!);
  }

  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

class Point1 {
  double? x; // Declare instance variable x, initially null.
  double? y; // Declare y, initially null.
}

double initialX = 1.5;

class Point3 {
  // OK, can access declarations that do not depend on `this`:
  double? x = initialX;

  // ERROR, can't access `this` in non-`late` initializer:
  // double? y = this.x;
  double? y;

  // OK, can access `this` in `late` initializer:
  late double? z = this.x;

  // OK, `this.x` and `this.y` are parameter declarations, not expressions:
  Point3(this.x, this.y);

  //https://dart.cn/language/classes/#static-methods
  static double distanceBetween(Point3 a, Point3 b) {

    var dx = (a.x ?? 0) - (b.x ?? 0);
    var dy = (a.y ?? 0) - (b.y ?? 0);
    return sqrt(dx * dx + dy * dy);
  }
}

class ProfileMark {
  final String name;
  final DateTime start = DateTime.now();

  ProfileMark(this.name);
  ProfileMark.unnamed() : name = '';
}

//https://dart.cn/language/classes/#implicit-interfaces

class ImmutablePoint {
  final double x;
  final double y;

  const ImmutablePoint(this.x, this.y);
}

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final String _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Impostor implements Person {
  String get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

// class Point4 implements Comparable, Location {
//   //...
// }

class Queue {
  static const initialCapacity = 16;

}

void main(List<String> arguments) {
  // https://dart.cn/language/classes/#using-class-members
  var p = Point(2, 2);

  // Get the value of y.
  assert(p.y == 2);

  // Invoke distanceTo() on p.
  double distance = p.distanceTo(Point(4, 4));
  // If p is non-null, set a variable equal to its y value.
  var a = p?.y;

  //https://dart.cn/language/classes/#using-constructors
  var p1 = Point(2, 2);
  var p2 = Point.fromJson({'x': 1, 'y': 2});
  // var p1 = new Point(2, 2);
  // var p2 = new Point.fromJson({'x': 1, 'y': 2});
  var p3 = const ImmutablePoint(2, 2);
  var a1 = const ImmutablePoint(1, 1);
  var b1 = const ImmutablePoint(1, 1);

  assert(identical(a1, b1)); // They are the same instance!
  // Lots of const keywords here.
  const pointAndLine = const {
    'point': const [const ImmutablePoint(0, 0)],
    'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
  };
  // Only one const, which establishes the constant context.
  const pointAndLineNew = {
    'point': [ImmutablePoint(0, 0)],
    'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
  };
  var a2 = const ImmutablePoint(1, 1); // Creates a constant
  var b2 = ImmutablePoint(1, 1); // Does NOT create a constant

  assert(!identical(a2, b2)); // NOT the same instance!

  //https://dart.cn/language/classes/#getting-an-objects-type
  print('The type of a is ${a.runtimeType}');

  //https://dart.cn/language/classes/#instance-variables
  var point = Point1();
  point.x = 4; // Use the setter method for x.
  assert(point.x == 4); // Use the getter method for x.
  assert(point.y == null); // Values default to null.

  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));

  //https://dart.cn/language/classes/#static-variables
  assert(Queue.initialCapacity == 16);

  var a3 = Point3(2, 2);
  var b3 = Point3(4, 4);
  var distance3 = Point3.distanceBetween(a3, b3);
  assert(2.8 < distance3 && distance3 < 2.9);
  print(distance3);
}
